﻿using System;
using System.Collections.Generic;

namespace Needle.Utils
{
    /// <summary>
    /// A range of integers.
    /// </summary>
    public class Range: IEnumerable<int>
    {

        /// <summary>
        /// Initializes an empty range
        /// </summary>
        public Range()
        {
            _End = 0;
            _Start = 0;
        }

        /// <summary>
        /// Initializes a new range from start to end
        /// </summary>
        public Range(int start, int end)
        {
            _Start = start;
            _End = end;
        }

        private readonly int _End;
        /// <summary>
        /// The end of the range
        /// </summary>
        public int End
        {
            get { return _End; }
        }

        private readonly int _Start;
       /// <summary>
       /// the start of the range
       /// </summary>
        public int Start
        {
            get { return _Start; }
        }

        /// <summary>
        /// returns true if i is contained within this range.
        /// </summary>
        public bool Contains(int i)
        {
            if (_Start > _End)
                return _End <= i && i <= _Start;
            else
                return _Start <= i && i <= _End;
        }

        /// <summary>
        /// returns true if r is contained within this range.
        /// </summary>
        public bool Contains(Range r)
        {
            return Contains(this, r);
        }
        /// <summary></summary>
        public static bool Contains(Range r1, Range r2)
        {
            return r1.Contains(r2.Start)
                && r1.Contains(r2.End);
        }
        /// <summary></summary>
        public bool Intersects(Range r)
        {
            return Intersects(this, r);
        }
        /// <summary></summary>
       public static bool Intersects(Range r1, Range r2)
        {
            return r1.Contains(r2.Start) 
                || r1.Contains(r2.End) 
                || r2.Contains(r1.Start) 
                || r2.Contains(r1.End);
        }
       /// <summary></summary>
         public static Range InterSection(Range r1, Range r2)
        {
            Range a = r1.Normalize();
            Range b = r2.Normalize();
            return new Range(Math.Max(a.Start, b.Start), Math.Min(a.End, b.End));
        }
         /// <summary></summary>
        public static Range Union(Range r1, Range r2)
        {
            Range a = r1.Normalize();
            Range b = r2.Normalize();
            return new Range(Math.Min(a.Start, b.Start), Math.Max(a.End, b.End));
        }

        /// <summary>
        /// returns the reversed range
        /// </summary>
        public Range Reverse()
        {
            return new Range(_End, _Start);
        }
        /// <summary></summary>
        public Range Normalize()
        {
            if (_Start > _End)
                return Reverse();
            return this;
        }
        /// <summary></summary>
        public IEnumerator<int> GetEnumerator()
        {
            if (_Start > _End)
                for (int i = _End; i <= _Start; i++)
                    yield return i;
            else
                for (int i = _Start; i <= _End; i++)
                    yield return i;
            yield break;
        }

       System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

    }
}
